package ru.usu.gv.gui.behavior;

import ru.usu.gv.core.GraphCanvas;
import ru.usu.gv.gui.layout.fd.ForceDirectedLayout;
import ru.usu.gv.gui.layout.fd.ForceDirectedLayoutSettings;
import ru.usu.gv.uicomponents.UIEdge;
import ru.usu.gv.uicomponents.UIGraph;
import ru.usu.gv.uicomponents.UIVertex;

import javax.media.j3d.BoundingSphere;
import javax.vecmath.Point3d;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author spupyrev
 * 06.11.2009
 */
public class OnlineDynamicVisBehavior extends DynamicVisBehavior
{
	public OnlineDynamicVisBehavior(BoundingSphere bound)
	{
		super(bound);
	}

	@Override
	public void processStimulus(Enumeration arg0)
	{
		wakeupOn(w);

		System.out.println("Running online dynamic force-directed layout");

		ForceDirectedLayoutSettings settings = createLayoutSettings();
		ForceDirectedLayout layout = new ForceDirectedLayout(settings);
		//extract all graphs and layout them
		UIGraph currentGraph = GraphCanvas.getInstance().getCurrentGraph();
		List<Map<Integer, Map<Integer, Double>>> graphs = extractSlicedGraphs(currentGraph);
		boolean changed = false;
		for (int i = 0; i < graphs.size(); i++)
		{
			Map<Integer, Map<Integer, Double>> edges = graphs.get(i);
			Map<Integer, Point3d> initialPositions = extractInitialPositions(currentGraph, edges);
			Map<Integer, Point3d> mentalPositions = extractMentalPositions(currentGraph, graphs, i);
			Map<Integer, Point3d> positions = layout.run(edges, mentalPositions, initialPositions);
			if (setCoordinates(currentGraph, positions))
				changed = true;
		}

		if (!changed)
			setEnable(false);
		else
			currentGraph.draw();
	}

	private Map<Integer, Point3d> extractMentalPositions(UIGraph uiGraph, List<Map<Integer, Map<Integer, Double>>> graphs, int now)
	{
		Map<Integer, Point3d> mentalPositions = new HashMap();
		if (now == 0)
			return mentalPositions;

		Map<Integer, Map<Integer, Double>> prevGraph = graphs.get(now - 1);
		Map<Integer, Map<Integer, Double>> curGraph = graphs.get(now);

		Map<String, UIVertex> prevVertexes = new HashMap();
		for (int v : prevGraph.keySet())
			prevVertexes.put(uiGraph.getVertex(v).getLabel(), uiGraph.getVertex(v));

		for (int v : curGraph.keySet())
		{
			UIVertex uiv = uiGraph.getVertex(v);
			if (prevVertexes.containsKey(uiv.getLabel()))
			{
				Point3d p = new Point3d(prevVertexes.get(uiv.getLabel()).getPosition());
				p.z = uiv.getPosition().z;
				mentalPositions.put(v, p);
			}
		}

		return mentalPositions;
	}

	private List<Map<Integer, Map<Integer, Double>>> extractSlicedGraphs(UIGraph currentGraph)
	{
		List<Double> zz = new ArrayList();
		Map<Double, Map<Integer, Map<Integer, Double>>> graphs = new HashMap();
		for (UIVertex v : currentGraph.getVertexes())
		{
			double z = v.getPosition().z;
			if (!graphs.containsKey(z))
			{
				graphs.put(z, new HashMap());
				zz.add(z);
			}

			graphs.get(z).put(v.getVertex().getIndex(), new HashMap());
		}

		for (UIEdge e : currentGraph.getEdges())
		{
			UIVertex v = e.getV1();
			UIVertex u = e.getV2();
			if (v.getPosition().z != u.getPosition().z)
				continue;

			double z = v.getPosition().z;

			graphs.get(z).get(v.getVertex().getIndex()).put(u.getVertex().getIndex(), 1.0);
			graphs.get(z).get(u.getVertex().getIndex()).put(v.getVertex().getIndex(), 1.0);
		}

		Collections.sort(zz);
		List<Map<Integer, Map<Integer, Double>>> sortedResult = new ArrayList();
		for (Double z : zz)
			sortedResult.add(graphs.get(z));

		return sortedResult;
	}

}
